#include "bitutils.h"

// constructor -- init attacks
Bitutils::Bitutils()
{
}

//MOVE TO UTILS
// get square i of rotated board (90 degree clockwise)
size_t Bitutils::rotate90Clockwise(size_t i) {
    size_t fileOld = i%8;
    size_t rankOld = i/8;
    size_t rankNew = 7-fileOld;
    size_t fileNew = rankOld;
    return ( rankNew*8+fileNew );
}

// get square i of rotated board (90 degree counter-clockwise)
size_t Bitutils::rotate90CounterClockwise(size_t i) {
    size_t fileOld = i%8;
    size_t rankOld = i/8;
    size_t rankNew = fileOld;
    size_t fileNew = 7-rankOld;
    return ( rankNew*8+fileNew );
}

// input: square i,
// output: rank for these "/" oriented diagonals - used in rank-pattern conversion (rook -> bishop)
size_t Bitutils::diagA1H8RankTool(size_t i) {
    size_t rank = i/8 - 1;
    size_t file = i%8 - 1;

    size_t diagRank = 0;
    while (ISIN(file,0,7) && ISIN(rank,0,7)) {
        rank--;
        file--;
        diagRank++;
    }

    return diagRank;
}
// input: square i,
// output: rank for these "\" oriented diagonals - used in rank-pattern conversion (rook -> bishop)
size_t Bitutils::diagA8H1RankTool(size_t i) {
    size_t rank = i/8 + 1;
    size_t file = i%8 - 1;

    size_t diagRank = 0;
    while (ISIN(file,0,7) && ISIN(rank,0,7)) {
        rank++;
        file--;
        diagRank++;
    }

    return diagRank;
}

// check wheter bit at position i is set in U64
bool Bitutils::checkBit(U64 bitboard, size_t i) {
    // note: 1ULL is 64 bit value with first bit set
    return ( bitboard & (1ULL << i) );
}

// check wheter bit at position i is set in byte
bool Bitutils::checkBit8(unsigned char byte, size_t i) {
    return ( byte & (1U << i) );
}

// set bit at position i in U64
void Bitutils::setBit(U64& bitboard, size_t i) {
    // note: 1ULL is 64 bit value with first bit set
    bitboard |= (1ULL << i);
}

// set bit at position i in byte
void Bitutils::setBit8(unsigned char& byte, size_t i) {
    byte |= (1U << i);
}



// count number of bits on bitboard
unsigned int Bitutils::count(U64 bitboard)
{
    // using MIT HAKMEM algorithm, see http://graphics.stanford.edu/~seander/bithacks.html
    static const U64  M1 = 0x5555555555555555;  // 1 zero,  1 one ...
    static const U64  M2 = 0x3333333333333333;  // 2 zeros,  2 ones ...
    static const U64  M4 = 0x0f0f0f0f0f0f0f0f;  // 4 zeros,  4 ones ...
    static const U64  M8 = 0x00ff00ff00ff00ff;  // 8 zeros,  8 ones ...
    static const U64 M16 = 0x0000ffff0000ffff;  // 16 zeros, 16 ones ...
    static const U64 M32 = 0x00000000ffffffff;  // 32 zeros, 32 ones

    bitboard = (bitboard & M1 ) + ((bitboard >>  1) & M1 );   //put count of each  2 bits into those  2 bits
    bitboard = (bitboard & M2 ) + ((bitboard >>  2) & M2 );   //put count of each  4 bits into those  4 bits
    bitboard = (bitboard & M4 ) + ((bitboard >>  4) & M4 );   //put count of each  8 bits into those  8 bits
    bitboard = (bitboard & M8 ) + ((bitboard >>  8) & M8 );   //put count of each 16 bits into those 16 bits
    bitboard = (bitboard & M16) + ((bitboard >> 16) & M16);   //put count of each 32 bits into those 32 bits
    bitboard = (bitboard & M32) + ((bitboard >> 32) & M32);   //put count of each 64 bits into those 64 bits

    return (int)bitboard;
}

// get first bit (least number) of bitboard
 unsigned int Bitutils::firstOne(U64 bitboard)
{
       // De Bruijn Multiplication, see http://chessprogramming.wikispaces.com/BitScan
       // don't use this if bitboard = 0

       static const int INDEX64[64] = {
       63,  0, 58,  1, 59, 47, 53,  2,
       60, 39, 48, 27, 54, 33, 42,  3,
       61, 51, 37, 40, 49, 18, 28, 20,
       55, 30, 34, 11, 43, 14, 22,  4,
       62, 57, 46, 52, 38, 26, 32, 41,
       50, 36, 17, 19, 29, 10, 13, 21,
       56, 45, 25, 31, 35, 16,  9, 12,
       44, 24, 15,  8, 23,  7,  6,  5  };

       static const U64 DEBRUIJN64 = U64(0x07EDD5E59A4E28C2);

       // here you would get a warming: "unary minus operator applied to unsigned type",
       // that's intended and OK so I'll disable it
#pragma warning (disable: 4146)
       return INDEX64[((bitboard & -bitboard) * DEBRUIJN64) >> 58];
}

 // get last (greatest number) bit of bitboard
 unsigned int Bitutils::lastOne(U64 bitboard)
{
    // this is Eugene Nalimov's bitScanReverse
       // use firstOne if you can, it is faster than lastOne.
       // don't use this if bitmap = 0

       int result = 0;
       if (bitboard > 0xFFFFFFFF)
       {
              bitboard >>= 32;
              result = 32;
       }
       if (bitboard > 0xFFFF)
       {
              bitboard >>= 16;
              result += 16;
       }
       if (bitboard > 0xFF)
       {
              bitboard >>= 8;
              result += 8;
       }

       int MS1BTABLE[256];
       // TODO !!!!!!!!!!! EXTERNAL CALC
       for (int i = 0; i < 256; i++)
           {
               MS1BTABLE[i] = (
                   (i > 127) ? 7 :
                   (i >  63) ? 6 :
                   (i >  31) ? 5 :
                   (i >  15) ? 4 :
                   (i >   7) ? 3 :
                   (i >   3) ? 2 :
                   (i >   1) ? 1 : 0 );
           }

       return result + MS1BTABLE[bitboard];
}

 // get a Bitboard with one single bit at position i set
U64 Bitutils::Bit(size_t i) {
    return 1ULL << i;
}


